import sys
import os
import socket
import re
import hashlib
from pathlib import Path
from common.ini_operate import IniOperate
from common.sql_operate import SqlOperate
from common.log import logger
from config.config import CONFIG_PATH, DATA_PATH

ini = IniOperate(Path(CONFIG_PATH) / "config.ini")

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('8.8.8.8', 80))
current_ip = s.getsockname()[0]
pattern = r"10.0.0.\d+"
compile_instance = re.compile(pattern, flags=re.IGNORECASE)
if compile_instance.search(current_ip):
    db_ip = ini.read_value("database", "ip")
    db_port = ini.read_value("database", "port")
    web_ip = ini.read_value("web", "ip")
    web_port = ini.read_value("web", "port")
else:
    db_ip = ini.read_value("database", "ex_ip")
    db_port = ini.read_value("database", "ex_port")
    web_ip = ini.read_value("web", "ex_ip")
    web_port = ini.read_value("web", "ex_port")

db_name_web = ini.read_value("database", "web_database_name")
db_name_case = ini.read_value("database", "case_database_name")
db_username = ini.read_value("database", "username")
db_password = ini.read_value("database", "password")
web_url = "".join(("http://", web_ip, ":", web_port))
test_level = ini.read_value("test", "level")


class GetTestDataError(Exception):
    def __init__(self, info):
        self.info = info

    def __str__(self):
        logger.error(f"Fail to get test cases '{self.info}' from '{db_name_case}'.")


def encrypt_password(username: str, unencrypted_password: str) -> str:
    hashlib_instance = hashlib.md5()
    to_be_encrypt_string = username + unencrypted_password
    hashlib_instance.update(to_be_encrypt_string.encode("utf-8"))
    return hashlib_instance.hexdigest()


def get_test_cases(table_name: str = "single_interface_case", filed_name: str = "interface_name", filed_value: str = "",
                   reverse: bool = False):
    """
    测试前的测试用例获取，根据传入的测试用例名称从数据库中查找待测试的测试用例
    :param table_name: 从指定数据库表中获取测试用例
    :param filed_name: 数据库的测试用例表中，指定要查询的字段名称
    :param filed_value: 数据库的测试用例表中，指定字段值的前缀内容
    :param reverse: 正向还是反向查找，默认为正向，若是正向，则使用"like"查找数据，否则使用"not like"
    :return:
    """
    try:
        sql = SqlOperate(ip_addr=db_ip, port=int(db_port), db_name=db_name_case, username=db_username,
                         password=db_password)
        if not reverse:
            result = sql.select_all(f"select * from {table_name} where {filed_name} like '{filed_value}%';")
        else:
            result = sql.select_all(f"select * from {table_name} where {filed_name} not like '{filed_value}%';")

        if result["code"] == "000":
            return result["data"]
        else:
            raise GetTestDataError(filed_name)
    except Exception as e:
        logger.error(f"[{sys._getframe().f_code.co_name}] Fail to get test data.")
        logger.error(f"[{sys._getframe().f_code.co_name}] {e}")


def get_keyword_mapping(table_name: str = "keyword_mapping"):
    """
    测试前的测试用例获取，根据传入的测试用例名称从数据库中查找待测试的测试用例
    :param table_name: 从指定数据库表中获取测试用例
    :return:
    """
    try:
        sql = SqlOperate(ip_addr=db_ip, port=int(db_port), db_name=db_name_case, username=db_username,
                         password=db_password)
        result = sql.select_all(f"select keyword, value from {table_name};")
        keyword_mapping = {}
        if result["code"] == "000":
            for each in result.get("data"):
                keyword_mapping[each.get("keyword")] = each.get("value")
            return keyword_mapping
        else:
            raise GetTestDataError(table_name)
    except Exception as e:
        logger.error(f"[{sys._getframe().f_code.co_name}] Fail to get keyword mapping.")
        logger.error(f"[{sys._getframe().f_code.co_name}] {e}")


def prepare_db_data(sql_file_name: str):
    """
    执行测试前的数据库数据准备
    :param sql_file_name:
    :return:
    """
    try:
        if os.path.isabs(sql_file_name):
            sql_file_path = sql_file_name
        else:
            sql_file_path = Path(DATA_PATH) / sql_file_name
        os.system(f"mysql -u{db_username} -p{db_password} -h{db_ip} -P{db_port} {db_name_web} < {sql_file_path}")
        logger.info(f"[{sys._getframe().f_code.co_name}] Succeed in loading data from {sql_file_name}.")
    except Exception as e:
        logger.error(f"[{sys._getframe().f_code.co_name}] Fail to load data from {sql_file_name}.")
        logger.error(f"{e}")


def reset_db(sql_file_name: str):
    """
    执行测试后的数据库还原
    :param sql_file_name:
    :return:
    """
    try:
        sql_file_path = Path(DATA_PATH) / sql_file_name
        os.system(f"mysql -u{db_username} -p{db_password} -h{db_ip} -P{db_port} {db_name_web} < {sql_file_path}")
        logger.info(f"[{sys._getframe().f_code.co_name}] Succeed in resetting data from {sql_file_name}.")
    except Exception as e:
        logger.error(f"[{sys._getframe().f_code.co_name}] Fail to reset data from {sql_file_name}.")
        logger.error(f"{e}")


if __name__ == "__main__":
    get_keyword_mapping()
